{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "# 将PaddleDetection套件进行解压，路径看具体情况。\n",
    "# (为了保险起见，将套件保存至work/路径下，千万不要保存在data/下以及这两个文件夹外，作者有过惨痛的经历教训，不希望大家再出现此惨状。)\n",
    "\n",
    "!unzip -oq /home/aistudio/data/data112279/PaddleDetection-release-0.5.zip -d work/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "# 将PaddleDetection套件进行改名（改名记得写上套件路径及改名后期望的路径）\n",
    "\n",
    "!mv work/PaddleDetection-release-0.5 work/PaddleDetection"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "!unzip -o data/data85839/RBC.zip -d work/PaddleDetection/dataset/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "!mv work/PaddleDetection/dataset/RBC work/PaddleDetection/dataset/test_det"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "train.txt Has Writed 274 records!\n",
      "eval.txt Has Writed 69 records!\n"
     ]
    }
   ],
   "source": [
    "import os \n",
    "import random\n",
    "\n",
    "# 类别数量 \n",
    "file_saved = []   # 保存数据\n",
    "\n",
    "random.seed(2021)\n",
    "\n",
    "# voc数据路径问题\n",
    "# 根目录信息，子目录信息，files_img--该文件夹下的文件名称\n",
    "for _, _, files_img in os.walk('work/PaddleDetection/dataset/test_det/JPEGImages'):\n",
    "    random.shuffle(files_img)\n",
    "\n",
    "    for _, _, files_xml in os.walk('work/PaddleDetection/dataset/test_det/Annotations'):\n",
    "        # indexs = 0\n",
    "        # 1.jpg\n",
    "        # 1.xml\n",
    "        for i in range(len(files_img)):  # 遍历图片文件--一张一张的\n",
    "            for j in range(len(files_xml)):\n",
    "                # 匹配，与图片前缀名称一致的xml文件\n",
    "                # 前缀是否一致\n",
    "                if files_img[i][:-4] == files_xml[j][:-4]:\n",
    "                    # 图片的相对路径 + 空格 + 标注文件的相对路径 + '\\n'\n",
    "                    # jpeg, img -- join -> jpeg/img\n",
    "                    # JPEGImages/files_img[i]\n",
    "                    file_maked = os.path.join('JPEGImages', files_img[i]) + ' ' + os.path.join('Annotations', files_xml[j])  + '\\n'\n",
    "                    \n",
    "                    file_saved.append(file_maked)          # 每一个类别放在对应的缓存空间中\n",
    "                    break\n",
    "\n",
    "# example: 图片的相对路径 + 空格 + 标注文件的相对路径 + '\\n'\n",
    "\n",
    "# 训练集的划分\n",
    "# 训练集占80%的数据\n",
    "# 验证集/评估数据集：1-80% = 20%\n",
    "Train_percent = 0.8\n",
    "\n",
    "# train.txt保存\n",
    "with open('work/PaddleDetection/dataset/test_det/train.txt', 'w') as f:\n",
    "    # int(Train_percent * len(file_saved))\n",
    "    # final_index = int(len(file_saved)*Train_percent) - 1\n",
    "    f.writelines(file_saved[:int(len(file_saved)*Train_percent)])  # 写入多行数据\n",
    "    print('train.txt Has Writed {0} records!'.format(len(file_saved[:int(len(file_saved)*Train_percent)])))\n",
    "    \n",
    "# eval.txt保存\n",
    "with open('work/PaddleDetection/dataset/test_det/eval.txt', 'w') as f:\n",
    "    # final_index + 1 == int(len(file_saved)*Train_percent)\n",
    "    f.writelines(file_saved[int(len(file_saved)*Train_percent):])\n",
    "    print('eval.txt Has Writed {0} records!'.format(len(file_saved[int(len(file_saved)*Train_percent):])))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "%cd work/PaddleDetection/\n",
    "!pip install -r requirements.txt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**yolov3_darknet_voc.yml**\n",
    "```\n",
    "architecture: YOLOv3\n",
    "use_gpu: true\n",
    "max_iters: 70000\n",
    "log_iter: 20\n",
    "save_dir: output\n",
    "snapshot_iter: 2000\n",
    "metric: VOC\n",
    "map_type: 11point\n",
    "pretrain_weights: https://paddle-imagenet-models-name.bj.bcebos.com/DarkNet53_pretrained.tar\n",
    "weights: output/yolov3_darknet_voc/model_final\n",
    "num_classes: 1\n",
    "use_fine_grained_loss: false\n",
    "\n",
    "YOLOv3:\n",
    "  backbone: DarkNet\n",
    "  yolo_head: YOLOv3Head\n",
    "\n",
    "DarkNet:\n",
    "  norm_type: sync_bn\n",
    "  norm_decay: 0.\n",
    "  depth: 53\n",
    "\n",
    "YOLOv3Head:\n",
    "  anchor_masks: [[6, 7, 8], [3, 4, 5], [0, 1, 2]]\n",
    "  anchors: [[10, 13], [16, 30], [33, 23],\n",
    "            [30, 61], [62, 45], [59, 119],\n",
    "            [116, 90], [156, 198], [373, 326]]\n",
    "  norm_decay: 0.\n",
    "  yolo_loss: YOLOv3Loss\n",
    "  nms:\n",
    "    background_label: -1\n",
    "    keep_top_k: 100\n",
    "    nms_threshold: 0.45\n",
    "    nms_top_k: 1000\n",
    "    normalized: false\n",
    "    score_threshold: 0.01\n",
    "\n",
    "YOLOv3Loss:\n",
    "  ignore_thresh: 0.7\n",
    "  label_smooth: false\n",
    "\n",
    "LearningRate:\n",
    "  base_lr: 0.00025\n",
    "  schedulers:\n",
    "  - !PiecewiseDecay\n",
    "    gamma: 0.1\n",
    "    milestones:\n",
    "    - 55000\n",
    "    - 62000\n",
    "  - !LinearWarmup\n",
    "    start_factor: 0.\n",
    "    steps: 1000\n",
    "\n",
    "OptimizerBuilder:\n",
    "  optimizer:\n",
    "    momentum: 0.9\n",
    "    type: Momentum\n",
    "  regularizer:\n",
    "    factor: 0.0005\n",
    "    type: L2\n",
    "\n",
    "_READER_: 'yolov3_reader.yml'\n",
    "TrainReader:\n",
    "  inputs_def:\n",
    "    fields: ['image', 'gt_bbox', 'gt_class', 'gt_score']\n",
    "    num_max_boxes: 50\n",
    "  dataset:\n",
    "    !VOCDataSet\n",
    "    dataset_dir: dataset/test_det\n",
    "    anno_path: train.txt\n",
    "    use_default_label: false\n",
    "    with_background: false\n",
    "\n",
    "EvalReader:\n",
    "  inputs_def:\n",
    "    fields: ['image', 'im_size', 'im_id', 'gt_bbox', 'gt_class', 'is_difficult']\n",
    "    num_max_boxes: 50\n",
    "  dataset:\n",
    "    !VOCDataSet\n",
    "    dataset_dir: dataset/test_det\n",
    "    anno_path: eval.txt\n",
    "    use_default_label: false\n",
    "    with_background: false\n",
    "\n",
    "TestReader:\n",
    "  dataset:\n",
    "    !ImageFolder\n",
    "    use_default_label: false\n",
    "    with_background: false\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**yolov3_reader.yml**\n",
    "```\n",
    "TrainReader:\n",
    "  inputs_def:\n",
    "    fields: ['image', 'gt_bbox', 'gt_class', 'gt_score']\n",
    "    num_max_boxes: 50\n",
    "  dataset:\n",
    "    !COCODataSet\n",
    "      image_dir: dataset/test_det\n",
    "      anno_path: train.txt\n",
    "      dataset_dir: dataset/test_det\n",
    "      with_background: false\n",
    "  sample_transforms:\n",
    "    - !DecodeImage\n",
    "      to_rgb: True\n",
    "      with_mixup: True\n",
    "    - !MixupImage\n",
    "      alpha: 1.5\n",
    "      beta: 1.5\n",
    "    - !ColorDistort {}\n",
    "    - !RandomExpand\n",
    "      fill_value: [123.675, 116.28, 103.53]\n",
    "    - !RandomCrop {}\n",
    "    - !RandomFlipImage\n",
    "      is_normalized: false\n",
    "    - !NormalizeBox {}\n",
    "    - !PadBox\n",
    "      num_max_boxes: 50\n",
    "    - !BboxXYXY2XYWH {}\n",
    "  batch_transforms:\n",
    "  - !RandomShape\n",
    "    sizes: [320, 352, 384, 416, 448, 480, 512, 544, 576, 608]\n",
    "    random_inter: True\n",
    "  - !NormalizeImage\n",
    "    mean: [0.485, 0.456, 0.406]\n",
    "    std: [0.229, 0.224, 0.225]\n",
    "    is_scale: True\n",
    "    is_channel_first: false\n",
    "  - !Permute\n",
    "    to_bgr: false\n",
    "    channel_first: True\n",
    "  # Gt2YoloTarget is only used when use_fine_grained_loss set as true,\n",
    "  # this operator will be deleted automatically if use_fine_grained_loss\n",
    "  # is set as false\n",
    "  - !Gt2YoloTarget\n",
    "    anchor_masks: [[6, 7, 8], [3, 4, 5], [0, 1, 2]]\n",
    "    anchors: [[10, 13], [16, 30], [33, 23],\n",
    "              [30, 61], [62, 45], [59, 119],\n",
    "              [116, 90], [156, 198], [373, 326]]\n",
    "    downsample_ratios: [32, 16, 8]\n",
    "  batch_size: 8\n",
    "  shuffle: true\n",
    "  mixup_epoch: 250\n",
    "  drop_last: true\n",
    "  worker_num: 8\n",
    "  bufsize: 16\n",
    "  use_process: true\n",
    "\n",
    "\n",
    "EvalReader:\n",
    "  inputs_def:\n",
    "    fields: ['image', 'im_size', 'im_id']\n",
    "    num_max_boxes: 50\n",
    "  dataset:\n",
    "    !COCODataSet\n",
    "      image_dir: dataset/test_det\n",
    "      anno_path: eval.txt\n",
    "      dataset_dir: dataset/test_det\n",
    "      with_background: false\n",
    "  sample_transforms:\n",
    "    - !DecodeImage\n",
    "      to_rgb: True\n",
    "    - !ResizeImage\n",
    "      target_size: 608\n",
    "      interp: 2\n",
    "    - !NormalizeImage\n",
    "      mean: [0.485, 0.456, 0.406]\n",
    "      std: [0.229, 0.224, 0.225]\n",
    "      is_scale: True\n",
    "      is_channel_first: false\n",
    "    - !PadBox\n",
    "      num_max_boxes: 50\n",
    "    - !Permute\n",
    "      to_bgr: false\n",
    "      channel_first: True\n",
    "  batch_size: 1\n",
    "  drop_empty: false\n",
    "  worker_num: 8\n",
    "  bufsize: 16\n",
    "\n",
    "TestReader:\n",
    "  inputs_def:\n",
    "    image_shape: [3, 608, 608]\n",
    "    fields: ['image', 'im_size', 'im_id']\n",
    "  dataset:\n",
    "    !ImageFolder\n",
    "      anno_path: dataset/test_det/label_list.txt\n",
    "      with_background: false\n",
    "  sample_transforms:\n",
    "    - !DecodeImage\n",
    "      to_rgb: True\n",
    "    - !ResizeImage\n",
    "      target_size: 608\n",
    "      interp: 2\n",
    "    - !NormalizeImage\n",
    "      mean: [0.485, 0.456, 0.406]\n",
    "      std: [0.229, 0.224, 0.225]\n",
    "      is_scale: True\n",
    "      is_channel_first: false\n",
    "    - !Permute\n",
    "      to_bgr: false\n",
    "      channel_first: True\n",
    "  batch_size: 1\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "%cd work/PaddleDetection/\n",
    "!python tools/train.py -c configs/yolov3_darknet_voc.yml\\\n",
    "--eval\\\n",
    "--use_vdl True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "%cd work/PaddleDetection/\n",
    "!python tools/infer.py -c configs/yolov3_darknet_voc.yml\\\n",
    "-o weights='output/yolov3_darknet_voc/model_final.pdparams'\\\n",
    "--infer_dir 'dataset/test_det/JPEGImages'\\\n",
    "--output_dir 'output'\\\n",
    "--draw_threshold 0.1\\\n",
    "# --save_txt True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "!python tools/export_model.py -c configs/yolov3_darknet_voc.yml --output_dir=./inference_model \\\n",
    " -o weights=output/yolov3_darknet_voc/best_model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "config.json<br>\n",
    "```\n",
    "{\n",
    "\t\"network_type\":\"YOLOV3\",\n",
    "\n",
    "\t\"model_file_name\":\"__model__\",\n",
    "\t\"params_file_name\":\"__params__\",\n",
    "\n",
    "\t\"labels_file_name\":\"label_list.txt\",\n",
    "\n",
    "\t\"format\":\"RGB\",\n",
    "\t\"input_width\":608,\n",
    "\t\"input_height\":608,\n",
    "\t\t\n",
    "\t\"mean\":[123.675, 116.28, 103.53],\n",
    "    \"scale\":[0.0171248, 0.017507, 0.0174292],\n",
    "\t\"threshold\":0.01\n",
    "}\n",
    "```\n",
    "image.json\n",
    "```\n",
    "{\n",
    "    \"model_config\": \"../../../res/models/detection/yolov3\",\n",
    "    \"input\": {\n",
    "        \"type\": \"image\",\n",
    "        \"path\": \"../../../res/models/detection/yolov3/img/RBC.jpg\"\n",
    "    },\n",
    "    \"debug\": {\n",
    "        \"display_enable\": true,\n",
    "        \"predict_log_enable\": true,\n",
    "        \"predict_time_log_enable\": false\n",
    "    }\n",
    "}\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "部署代码：\n",
    "```\n",
    "cd /root/workspace/PaddleLiteDemo/C++/build\n",
    "./detection ../../configs/detection/yolov3/image.json\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "3. 主动式miniDP公转HDMI母转换线：来连接EdgeBoard和HDMI显示器。<br>\n",
    "参考链接：https://aim.baidu.com/product/649bd2ab-65ef-480d-b1bf-2ba8f10059ab<br>\n",
    "建议使用eb的原产线，因为市场上的线质量参差不齐。\n",
    "\n",
    "<img style=\"display: block; margin: 0 auto;\" \n",
    "    src=\"https://ai-studio-static-online.cdn.bcebos.com/28fb1ffdb2384c5da2b180074e5e19a9186a86dd54824a1ab8b81e9c37fb9200\" width = \"50%\" height = \"50%\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 调用摄像头"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. 安装驱动（在eb终端输入命令）\n",
    "\n",
    "```\n",
    "insmod /root/workspace/driver/driver/ch341.ko\n",
    "```\n",
    "```\n",
    "insmod /root/workspace/driver/driver/usbserial.ko\n",
    "```\n",
    "```\n",
    "insmod /root/workspace/driver/driver/fpgadrv.ko\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. 测试摄像头（在eb终端输入命令）\n",
    "摄像头参考链接：https://m.tb.cn/h.fRe4a6u?sm=0deb57<br>\n",
    "本人使用的是usb工业摄像头jpg/YUY2高速 HF877_3mm_90度无畸变60帧。\n",
    "\n",
    "<img style=\"display: block; margin: 0 auto;\" \n",
    "    src=\"https://ai-studio-static-online.cdn.bcebos.com/1120088a4c934955a50a73292e2ede9b9083de0305734ca3abe71676cc6147b8\" width = \"50%\" height = \"50%\" />\n",
    "\n",
    " "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "测试脚本：test_onecamera.py（由郑博培男神贡献的脚本，在此感谢郑博培男神，此脚本我已上传至文件中，大家有需要的可以自行下载）。<br>\n",
    "\n",
    "```\n",
    "python3 test_camera.py\n",
    "```\n",
    "\n",
    "能看到显示屏上有个蓝色的圈圈以及eb终端上有test！以及坐标，就说明摄像头测试成功。\n",
    "\n",
    "<img style=\"display: block; margin: 0 auto;\" \n",
    "    src=\"https://ai-studio-static-online.cdn.bcebos.com/88ded36da6ea4d7e8380a68cc93d295a9533f924efa24187b5628ea4fd9b6c1d\" width = \"50%\" height = \"50%\" />\n",
    "\n",
    "测试完，按Ctrl+C退出。\n",
    "\n",
    "有点遗憾的是，很抱歉没完成摄像头预测，没能帮到大家。希望有大佬可以解决这个摄像头预测。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "model、params(前两个文件名前后都有__,由于打上去会变成字体加粗，就省去了）、detectionResult、config.json、image.json、label.txt文件都上传至项目文件中，大家可以按照步骤自己训练、调参，也可以体验下本项目训练出来的模型参数与在板子上预测出来的结果图。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 七、总结与升华\n",
    "\n",
    "部署首先得把模型训练正常，并且正确导出模型，模型要能用Netron[https://netron.app/](https://netron.app/)（因此网站用特殊工具才能打开，所以我将PC端启动程序放置在项目文件中）打开，不然可能模型错误。拿到板子前要先测试，看看tf卡是不是好的。板子要注意用1.8.x版本训练，比较稳定，并且要看好板子支持的部署模型，之前上课期间因不知eb不支持ppyolo模型。后来知道了，就换成了yolov3。并且我也由2.1的两个模型换成了1.8.x来运行模型。重要东西一定要保存在work/目录下，防止某一天重启环境，notebook桌面里的文件丢失。特别是训练特别久的模型。模型导出后最好不要改模型文件的名字，以免部署失败。要注意image.json下的文件路径。希望这个项目可以帮助到大家。本以为这个项目要完不成了，突然部署的最后一天来了希望。这真是20岁第一天的好兆头。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 个人简介\n",
    "请大家多多支持。欢迎fork、喜欢、分享、评论。本人能力有限，经验不足，若有不足，欢迎指正，谢谢大家！<br>\n",
    "> 姓名：林勇\n",
    "\n",
    "> 学校：西安科技大学高新学院\n",
    "\n",
    "> 学历：本科二年级在读\n",
    "\n",
    "> 专业：智能科学与技术\n",
    "\n",
    "> 擅长领域：cv（目标检测）\n",
    "\n",
    "> AI Studio链接：我在AI Studio上获得白银等级，点亮6个徽章，来互关呀~<br>\n",
    "[https://aistudio.baidu.com/aistudio/personalcenter/thirdview/691883](https://aistudio.baidu.com/aistudio/personalcenter/thirdview/691883)\n",
    "\n",
    "> github链接：[https://github.com/FZSWJLY](https://github.com/FZSWJLY)\n",
    "\n",
    "> qq：1431364191\n",
    "\n",
    "> 微信：programmerxiaoyong\n",
    "<img style=\"display: block; margin: 0 auto;\" src=\"https://ai-studio-static-online.cdn.bcebos.com/5eaf05881cc441769bee9165e93f73473ac31a5ff65d44ada3c3343138cba405\" width = \"50%\" height = \"50%\" />"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "py35-paddle1.2.0"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
